Cleanest façon d'obtenir dernier élément de Python iterator
-
22-09-2019 - |
Question
Quelle est la meilleure façon d'obtenir le dernier élément d'un iterator en Python 2.6? Par exemple, disons
my_iter = iter(range(5))
Quel est le plus court code / manière la plus propre d'obtenir 4
de my_iter
?
Je pourrais le faire, mais il ne semble pas très efficace:
[x for x in my_iter][-1]
La solution
item = defaultvalue
for item in my_iter:
pass
Autres conseils
Utilisez un deque
de taille 1.
from collections import deque
#aa is an interator
aa = iter('apple')
dd = deque(aa, maxlen=1)
last_element = dd.pop()
Si vous utilisez 3.x python:
*_, last = iterator # for a better understanding check PEP 448
print(last)
si vous utilisez Python 2.7:
last = next(iterator)
for last in iterator:
continue
print last
NB:
En général, la solution présentée ci-dessus est ce dont vous avez besoin pour les cas réguliers, mais si vous faites affaire avec une grande quantité de données, il est plus efficace d'utiliser un deque
de taille 1. ( la source )
from collections import deque
#aa is an interator
aa = iter('apple')
dd = deque(aa, maxlen=1)
last_element = dd.pop()
Probablement la peine d'utiliser __reversed__
si elle est disponible
if hasattr(my_iter,'__reversed__'):
last = next(reversed(my_iter))
else:
for last in my_iter:
pass
Aussi simple que:
max(enumerate(the_iter))[1]
Il est peu probable d'être plus rapide que le vide pour la boucle en raison du lambda, mais peut-être cela donnera une idée de quelqu'un d'autre
reduce(lambda x,y:y,my_iter)
Si le iter est vide, un TypeError est élevé
Il y a cette
list( the_iter )[-1]
Si la longueur de l'itération est vraiment épique - si longtemps que matérialisant la liste mémoire d'échappement -. Alors vous avez vraiment besoin de repenser la conception
J'utiliser reversed
, sauf qu'il ne prend des séquences au lieu de itérateurs, qui semble plutôt arbitraire.
De toute façon vous le faites, vous aurez à courir à travers l'ensemble iterator. À un maximum d'efficacité, si vous n'avez pas besoin iterator jamais, vous pouvez simplement poubelle toutes les valeurs:
for last in my_iter:
pass
# last is now the last item
Je pense que c'est une solution sous-optimale, cependant.
Le toolz bibliothèque offre une belle solution:
from toolz.itertoolz import last
last(values)
Mais l'ajout d'une dépendance non-core peut-être pas la peine pour l'utiliser seulement dans ce cas.
Voir ce code pour quelque chose de semblable:
http://excamera.com/sphinx/article-islast.html
vous pouvez l'utiliser pour ramasser le dernier élément avec:
[(last, e) for (last, e) in islast(the_iter) if last]
Je voudrais simplement utiliser next(reversed(myiter))
La question est sur le point d'obtenir le dernier élément d'un itérateur, mais si votre iterator est créé en appliquant des conditions à une séquence, puis inversée peut être utilisé pour trouver la « première » d'une séquence inversée, ne regardant que les éléments nécessaires , par application inverse de la séquence elle-même.
Un exemple artificiel,
>>> seq = list(range(10))
>>> last_even = next(_ for _ in reversed(seq) if _ % 2 == 0)
>>> last_even
8
Sinon, pour itérateurs infini vous pouvez utiliser:
from itertools import islice
last = list(islice(iterator(), 1000))[-1] # where 1000 is number of samples
Je pensais que ce serait plus lent que deque
mais il est aussi rapide et il est en fait plus rapide que pour la méthode de la boucle (en quelque sorte)
La question est erronée et ne peut conduire à une réponse qui est complexe et inefficace. Pour obtenir un itérateur, bien sûr, vous commencez à partir de quelque chose qui est itératives, qui dans la plupart des cas offrir une façon plus directe d'accéder au dernier élément.
Une fois que vous créez un itérateur d'un itérables vous êtes coincé dans passant par les éléments, parce que c'est la seule chose qu'un itérables fournit.
Ainsi, la façon la plus claire et efficace est de ne pas créer l'itérateur en premier lieu, mais d'utiliser les méthodes d'accès natif du itérables.